<?php

/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Validate
 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: Validate.php 24593 2012-01-05 20:35:02Z matthew $
 */
/**
 * @see Zend_Validate_Interface
 */
require_once 'Zend/Validate/Interface.php';

/**
 * @category   Zend
 * @package    Zend_Validate
 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Validate implements Zend_Validate_Interface {

	/**
	 * Validator chain
	 *
	 * @var array
	 */
	protected $_validators = array();

	/**
	 * Array of validation failure messages
	 *
	 * @var array
	 */
	protected $_messages = array();

	/**
	 * Default Namespaces
	 *
	 * @var array
	 */
	protected static $_defaultNamespaces = array();

	/**
	 * Array of validation failure message codes
	 *
	 * @var array
	 * @deprecated Since 1.5.0
	 */
	protected $_errors = array();

	/**
	 * Adds a validator to the end of the chain
	 *
	 * If $breakChainOnFailure is true, then if the validator fails, the next validator in the chain,
	 * if one exists, will not be executed.
	 *
	 * @param  Zend_Validate_Interface $validator
	 * @param  boolean                 $breakChainOnFailure
	 * @return Zend_Validate Provides a fluent interface
	 */
	public function addValidator(Zend_Validate_Interface $validator, $breakChainOnFailure = false) {
		$this->_validators[] = array(
			'instance' => $validator,
			'breakChainOnFailure' => (boolean) $breakChainOnFailure
		);
		return $this;
	}

	/**
	 * Returns true if and only if $value passes all validations in the chain
	 *
	 * Validators are run in the order in which they were added to the chain (FIFO).
	 *
	 * @param  mixed $value
	 * @return boolean
	 */
	public function isValid($value) {
		$this->_messages = array();
		$this->_errors = array();
		$result = true;
		foreach ($this->_validators as $element) {
			$validator = $element['instance'];
			if ($validator->isValid($value)) {
				continue;
			}
			$result = false;
			$messages = $validator->getMessages();
			$this->_messages = array_merge($this->_messages, $messages);
			$this->_errors = array_merge($this->_errors, array_keys($messages));
			if ($element['breakChainOnFailure']) {
				break;
			}
		}
		return $result;
	}

	/**
	 * Defined by Zend_Validate_Interface
	 *
	 * Returns array of validation failure messages
	 *
	 * @return array
	 */
	public function getMessages() {
		return $this->_messages;
	}

	/**
	 * Defined by Zend_Validate_Interface
	 *
	 * Returns array of validation failure message codes
	 *
	 * @return array
	 * @deprecated Since 1.5.0
	 */
	public function getErrors() {
		return $this->_errors;
	}

	/**
	 * Returns the set default namespaces
	 *
	 * @return array
	 */
	public static function getDefaultNamespaces() {
		return self::$_defaultNamespaces;
	}

	/**
	 * Sets new default namespaces
	 *
	 * @param array|string $namespace
	 * @return null
	 */
	public static function setDefaultNamespaces($namespace) {
		if (!is_array($namespace)) {
			$namespace = array((string) $namespace);
		}

		self::$_defaultNamespaces = $namespace;
	}

	/**
	 * Adds a new default namespace
	 *
	 * @param array|string $namespace
	 * @return null
	 */
	public static function addDefaultNamespaces($namespace) {
		if (!is_array($namespace)) {
			$namespace = array((string) $namespace);
		}

		self::$_defaultNamespaces = array_unique(array_merge(self::$_defaultNamespaces, $namespace));
	}

	/**
	 * Returns true when defaultNamespaces are set
	 *
	 * @return boolean
	 */
	public static function hasDefaultNamespaces() {
		return (!empty(self::$_defaultNamespaces));
	}

	/**
	 * @param  mixed    $value
	 * @param  string   $classBaseName
	 * @param  array    $args          OPTIONAL
	 * @param  mixed    $namespaces    OPTIONAL
	 * @return boolean
	 * @throws Zend_Validate_Exception
	 */
	public static function is($value, $classBaseName, array $args = array(), $namespaces = array()) {
		$namespaces = array_merge((array) $namespaces, self::$_defaultNamespaces, array('Zend_Validate'));
		$className = ucfirst($classBaseName);
		try {
			if (!class_exists($className, false)) {
				require_once 'Zend/Loader.php';
				foreach ($namespaces as $namespace) {
					$class = $namespace . '_' . $className;
					$file = str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
					if (Zend_Loader::isReadable($file)) {
						Zend_Loader::loadClass($class);
						$className = $class;
						break;
					}
				}
			}

			$class = new ReflectionClass($className);
			if ($class->implementsInterface('Zend_Validate_Interface')) {
				if ($class->hasMethod('__construct')) {
					$keys = array_keys($args);
					$numeric = false;
					foreach ($keys as $key) {
						if (is_numeric($key)) {
							$numeric = true;
							break;
						}
					}

					if ($numeric) {
						$object = $class->newInstanceArgs($args);
					} else {
						$object = $class->newInstance($args);
					}
				} else {
					$object = $class->newInstance();
				}

				return $object->isValid($value);
			}
		} catch (Zend_Validate_Exception $ze) {
			// if there is an exception while validating throw it
			throw $ze;
		} catch (Exception $e) {
			// fallthrough and continue for missing validation classes
		}

		require_once 'Zend/Validate/Exception.php';
		throw new Zend_Validate_Exception("Validate class not found from basename '$classBaseName'");
	}

	/**
	 * Returns the maximum allowed message length
	 *
	 * @return integer
	 */
	public static function getMessageLength() {
		require_once 'Zend/Validate/Abstract.php';
		return Zend_Validate_Abstract::getMessageLength();
	}

	/**
	 * Sets the maximum allowed message length
	 *
	 * @param integer $length
	 */
	public static function setMessageLength($length = -1) {
		require_once 'Zend/Validate/Abstract.php';
		Zend_Validate_Abstract::setMessageLength($length);
	}

	/**
	 * Returns the default translation object
	 *
	 * @return Zend_Translate_Adapter|null
	 */
	public static function getDefaultTranslator($translator = null) {
		require_once 'Zend/Validate/Abstract.php';
		return Zend_Validate_Abstract::getDefaultTranslator();
	}

	/**
	 * Sets a default translation object for all validation objects
	 *
	 * @param Zend_Translate|Zend_Translate_Adapter|null $translator
	 */
	public static function setDefaultTranslator($translator = null) {
		require_once 'Zend/Validate/Abstract.php';
		Zend_Validate_Abstract::setDefaultTranslator($translator);
	}

}
